#! /usr/bin/env python3
'''
输入md模板文件，然后使用json作为变量的输入，导出最终的md的文件。
md模板中有以下类型：
* 字符串：{{string}}
* 图片： ![title]{{image_}},支持单图、多图以及html结尾的动图， 末尾带* ，则自动添加下载链接
* 表格： ![title]{{table_}}，自动将第一个表格转为md，末尾带*，自动添加下载链接，是否需要压缩后下载
* 下载： ![title]{{download_}}
* 跳转链接: ![title]{{href_}} , 构建跳转链接。
* json： ![title]{{json_}} , 后面的注释以@开头
* 小工具：![参数]{{smalltool_}}

## 功能：
* 添加图片width的维持原比例缩放
* 整理文件到upload目录下，并进行压缩成文件
* 支持跳转  SmallTool:(输入文件:upload/*_differential/*venn/*.report.xls),(首行为表头:否),(边框类型:虚线),(边框颜色:粉红,紫罗兰,天蓝色,纯黄,马鞍
    色),(填充颜色:粉红,紫罗兰,天蓝色,纯黄,马鞍色),(透明度:5),(id:bc088020d5c64df9a712d5f5b0f94487),(version:2.0.1),0,,,>
* 自动增加标题级别
* 增加公司信息


## 注意
* 为了避免风险，所有文件的文件名最好带有样品名，或者保持唯一；
json里有*/a.pdf ，这种会导致copy 文件到upload的时候，相同文件名覆盖 ，因此建议最好文件名是不一样， 加上样品名
* input.json 和template.md 必须平级，同时json里用相对路径


## 如何添加一个新功能
1.  134和135 添加一个新类型
2.   279 添加一个类型
3. 264 增加一个动作。


## reference
* https://c.solargenomics.com//final-report/test.html#1.6%20%20%E5%B0%8F%E5%B7%A5%E5%85%B7

'''
import argparse
import sys
import os
import re
from jinja2 import Environment, FileSystemLoader,StrictUndefined,meta,DebugUndefined
import json
from pytablewriter import MarkdownTableWriter
from pytablewriter.style import Style
import glob
from shutil import copyfile
import zipfile
from PIL import Image
import collections
from pprint import pprint
bindir = os.path.abspath(os.path.dirname(__file__))

__author__='Liu Tao'
__mail__= 'taoliu@annoroad.com'

pat1 = re.compile('{{(\S*)}}')
pat2 = re.compile('\[(.*?)\]')

class Content():
    coder = {1:0 , 2:0 , 3:0}
    def __init__(self , line , config,  bool_pdf= False ):
        self.line = line.lstrip()
        self.downloadable = False
        self.config = config
        self.description = []
        self.out_line = ''
        self.bool_pdf = bool_pdf
        self.add_title_number()
    def add_title_number(self):
        '''
        add title coding number after ### symbols
        '''
        if self.line.startswith('#'):
            count = 0 
            for i in self.line:
                if i == '#':
                    count += 1
            if count <=4 :
                header = self.code_header(count)
                self.line = '\n' +  '#' * count + ' ' + header + self.line[count:]
            else:
                pass
        else:
            pass 
    def code_header(self , count):
        '''
        coding title number
        '''
        coder = Content.coder 
        if count == 1 :
            return(' ')
        elif count == 2 : 
            coder[1] += 1 
            coder[2] = 0 
            coder[3] = 0
            return('{0}'.format(coder[1]))
        elif count == 3:
            coder[2] += 1
            coder[3] = 0 
            return('{0}.{1}'.format(coder[1] , coder[2]))
        elif count == 4 :
            coder[3] += 1 
            return('{0}.{1}.{2}'.format(coder[1] , coder[2] , coder[3]))
        else:
            pass

    def is_contain_variable(self ):
        '''
        check a line whether contain a variable
        '''
        s1 = pat1.search(self.line)   ## for {{}}
        s2 = pat2.search(self.line)   ## for []
        if s1 :
            self.variable = s1.group(1)
            if self.line.startswith('!') and s2:
                self.title = s2.group(1)
                if self.line.rstrip().endswith('*'):
                    self.downloadable = True
            return(True)
        else:
            self.variable = None
            self.title = None
            return(False)
    def type_of_variable(self):
        if self.variable.startswith('table_'):
            self.type = 'table'
        elif self.variable.startswith('image_'):
            self.type = 'image'
        elif self.variable.startswith('download_'):
            self.type = 'download'
        elif self.variable.startswith('json_'):
            self.type = 'json'
        elif self.variable.startswith('smalltool_'):
            self.type = 'smalltool'
        elif self.variable.startswith('href_'):  # ![title]{{href_}}
            self.type = 'href'
        else :
            self.type = 'string'
    def output_table(self , num ):
        r_str = '<center>表{0} {1}</center> \n\n{{{{{2}}}}}\n\n'.format(num , self.title ,self.variable)
        self.out_line = r_str
    def output_html_image(self , num):
        self.out_line = '''<p align="center"><iframe height="400px" width="300px" \
            src="{{{{{0}}}}}" frameborder=0 allowfullscreen></iframe></p><center> \
            图{1} {2}</center>'''.format(self.variable , num, self.title)
    def output_multi_html_image(self , a_list , num ):
        if self.bool_pdf:
            self.out_line = '''<div><img  \
               src="{0}.png" style="display: block;margin: 0 auto;" width="300px" height="400px"  >\
               </div><center>图{1} {2}</center>\n\n'''.format( a_list[0] , num , self.title)
        else:
            for i,j in enumerate(a_list):
                if i ==0 :
                    self.out_line = '''<div class="albumSlider"><div class="album"><div class="fullview"> \
            <img src="{0}.png" style=""></div> <div class="slider"> <div class="button movebackward" title="向上滚动"> \
            &lt;&lt;</div><div class="imglistwrap"> <ul class="imglist" style="top: 0;"> \
            <li class="current" html="{0}"><img src="{0}.png" alt="{1}"> </li> '''.format( j , self.title)
                else:
                    self.out_line += '''<li class="" html="{0}"><img src="{0}.png" alt="{1}"></li>'''.format( j , self.title)
            self.out_line += '''</ul> </div> <div class="button moveforward" 
            title="向下滚动">&gt;&gt;</div></div> </div><center>图{0} {1}</center></div>'''.format(num , self.title)
    def output_multi_image(self, a_list ,num , w, h):
        if self.bool_pdf:
            self.out_line = '''<div><img  \
               src="{0}" style="display: block;margin: 0 auto;" width="{4}px" height="{3}px"  >\
               </div><center>图{1} {2}</center>\n\n'''.format( a_list[0] , num , self.title , h ,w )
        else:
            for i,j in enumerate(a_list):
                if i == 0:
                    self.out_line = '''<div class="albumSlider"><div class="album"> \
            <div class="fullview"><img src="{0}" style=""></div><div class="slider"> \
            <div class="button movebackward" title="向上滚动">&lt;&lt;</div> \
            <div class="imglistwrap"><ul class="imglist" style="top: 0;">\
            <li class="current"><img src="{0}" alt="{1}"></li>'''.format(j , self.title)
                else:   
                    self.out_line+='''  <li class=><img src="{0}" alt="{1}"></li>'''.format(j , self.title)
            self.out_line += '''</ul> </div> <div class="button moveforward" title="向下滚动"> \
            &gt;&gt;</div></div> </div><center>图{0} {1}</center></div>'''.format(num , self.title)
    def output_single_image(self , num , w ,h ):
        self.out_line = '''<div><img  \
        src="{{{{{0}}}}}" style="display: block;margin: 0 auto;" width="{4}px" height="{3}px"  >\
        </div><center>图{1} {2}</center>\n\n'''.format( self.variable , num , self.title , h ,w )
    def output_download(self , name=False):
        if self.bool_pdf:
            pass
        else:
            if not name : name = self.variable
            #self.out_line += '''<div>&emsp;&emsp;{0}下载链接：</div>\n'''.format(self.title)
            self.out_line += '''<a style="cursor:pointer;text-align: right;display: block;" href="{{{{{0}}}}}">\
                <img src="https://source.solargenomics.com/source/report/download.png"/></a>\n'''.format(name )
    def output_json(self , project , keys , group):
        if self.bool_pdf:
            pass
        else:
            self.out_line = '''<div class="fileListBox"><div class="downloadBtn"></div>\
            <span class="leftBtn"></span><div class="fileListContent">\
                <img src="https://source.solargenomics.com/source/report/file.png" alt="文件图标"><ul>'''
            for i in keys:
                self.out_line += '<li url="table.html?idCode={0}&sourceKey={1}&group=g{2}"><p>{3}</p></li> '.format(project, i , group, keys[i])
            self.out_line += '</ul></div><span class="rightBtn"></span></div>'
    def output_smalltool(self ,a_list):
        if self.bool_pdf:
            pass
        else:
            self.out_line = ''' SmallTool:(输入文件:{{{{{0}}}}}){1},\n '''.format(self.variable, self.title)
            tool_config = self.config['smalltools'][self.title]
            self.out_line = '''<div code={0[code]} name={1} version={0[version]}> 输入文件：<select class=c-tools name=infile>'''.format(tool_config , self.title)
            for i in a_list : 
                self.out_line+='<option value="{0}">{0}</option>'.format(i)
            self.out_line += '''</select> <button class="c-jump-btn">{0}</button></div>\n'''.format( self.title)
    def output_href(self ):
        self.out_line = '''<a href="{{{{{0}}}}}" target="_blank">{1}</a> '''.format(self.variable , self.title)
    def replace_content(self , inputs_dict , count , bool_local ,project):
        a_path = inputs_dict[self.variable]    
        if self.type == 'table':
            count['table'] += 1
            inputs_dict[self.variable] = a_path.file_to_table()
            self.output_table( count['table'] )
            if self.downloadable:
                a_path.zip_files()
                inputs_dict['{0}_zip'.format(self.variable)] = a_path.add_prefix('zip', project , bool_local)
                self.output_download( '{0}_zip'.format(self.variable) )
        elif self.type == 'image':
            count['image'] += 1 
            if a_path.path.endswith('html') or a_path.path.endswith('svg') :
                if '*' in a_path.path:
                    self.output_multi_html_image( a_path.add_prefix('all', project ,bool_local ) , count['image'] )

                else:
                    self.output_html_image( count['image'])
                    inputs_dict[self.variable] = a_path.add_prefix( 0 , project , bool_local  )
            else:
                if '*' in a_path.path:
                    w, h = a_path.adjust()
                    self.output_multi_image(a_path.add_prefix('all', project ,bool_local ) , count['image'] , w, h)
                else: 
                    inputs_dict[self.variable] = a_path.add_prefix( 0 , project ,bool_local)
                    w, h = a_path.adjust()
                    self.output_single_image(count['image'] , w, h)
            ## inputs_dict['{0}_zip'.format(self.variable)] = a_path.file1
            if self.downloadable:
                bool_image = True
                a_path.zip_files( bool_image )
                inputs_dict['{0}_zip'.format(self.variable)] =a_path.add_prefix('zip', project , bool_local)
                self.output_download( '{0}_zip'.format(self.variable) )
        elif self.type == 'download':
            a_path.zip_files()
            inputs_dict['{0}_zip'.format(self.variable)] = a_path.add_prefix('zip', project , bool_local)
            self.output_download( '{0}_zip'.format(self.variable))
        elif self.type == 'json':
            keys , group = a_path.to_json(self.description)
            self.output_json(project , keys , group)
            if self.downloadable:
                a_path.zip_files()
                inputs_dict['{0}_zip'.format(self.variable)] = a_path.add_prefix('zip', project , bool_local)
                self.output_download('{0}_zip'.format(self.variable))
        elif self.type == 'smalltool':
            self.output_smalltool(a_path.add_prefix('st', project , bool_local))
            #inputs_dict['{0}'.format(self.variable)] = a_path.add_prefix('st', project , bool_local)
            if self.downloadable:
                a_path.zip_files()
                inputs_dict['{0}_zip'.format(self.variable)] = a_path.add_prefix('zip', project , bool_local)
                self.output_download('{0}_zip'.format(self.variable))
        elif self.type == 'href':
            inputs_dict[self.variable] = a_path.add_prefix( 0 , project , bool_local )
            self.output_href()
        else:
            self.out_line = self.line

class Pathway():
    sourceKey = 0
    group = 0 
    file_mapping =[]
    def __init__(self , name , value , module_name ,  dirname , url , mode ): 
        self.module = module_name  ### module name 
        self.name = name   ## key 
        self.value = value ## value 
        self.dirname = dirname   ### old file dirname
        self.judge_type()  ## set self.type ,true is a file ,  then add old dirname into path to access file
        self.add_path()  
        self.choose_file()  ## glob all files to get a list with origin directory
        self.parameter = url 
        self.mode = mode 
    def judge_type(self):
        name =self.name
        if name.startswith('image') or name.startswith('table') or name.startswith('download') or name.startswith('json') or name.startswith('smalltool') or name.startswith('href'):
            self.type = True
        else:
            self.type = False
    def add_path(self):
        if self.type:
            self.path = '{0}/{1}'.format(self.dirname, self.value)
        else:
            self.path = self.value
    def choose_file(self):
        if '*' in self.path:
            all_file = self.get_all_files()
            self.file1 = all_file[0]
            self.filelist = all_file
        else:
            self.file1 = self.path
            self.filelist = [self.file1]
    def get_all_files(self):
        '''get all file from old path'''
        all_files = sorted(glob.glob( self.path ))
        if len(all_files):
            return(all_files)
        else:
            print("no file in {0}".format(self.path))
    def file_to_table(self , ts = False):
        '''output file1 into markdown table format'''
        header = []
        content = [] 
        number = 4 
        line_cutoff = 15
        with open(self.file1) as f_in:
            for count  , line in enumerate(f_in):
                tmp=line.rstrip().split('\t')
                if count == 0 :
                    header = tmp[:number]
                else:
                    content += [tmp[:number]]
                if count > line_cutoff : break
        writer = MarkdownTableWriter()
        #writer.table_name = "example_table"
        writer.headers = header 
        writer.value_matrix = content
        #writer.margin = 1
        #writer.set_style(i, Style(thousand_separator=" "))
        return('\n'+ writer.dumps() + '\n')
    def add_prefix(self , position , project , local ):
        '''
        position: which file , 0- single file; all: modify all files ; st: modify samtools files ;other: return zip file
        project :
        local : used for local or url
        '''
        #url = 'https://source.solargenomics.com/user/report'
        url = ''
        if self.mode == 'pipeline':
            url = self.parameter[0]
        else:
            url = "/".join(self.parameter[:2])

        f_modify = lambda p: p[p.find('upload',):] if 'upload' in p else p

        if position == 0:
            if local:
                return(self.file1)
            else:
                if self.file1.startswith('http'):
                    return (self.file1)
                else:
                    if self.mode=='pipeline':
                        return('{0}/{1}/{2}'.format(url , project ,  f_modify(self.file1)))
                    else:
                        return('{0}/{1}'.format(url , f_modify(self.file1)))
                        #self.newfilelist.append('{0}/{1}'.format(url , f_modify(i)))
        elif position == 'all':
            self.newfilelist = []
            for i in self.filelist:
                if local:
                    self.newfilelist.append(i)
                else:
                    if self.mode=='pipeline':
                        self.newfilelist.append('{0}/{1}/{2}'.format(url , project ,  f_modify(i)))
                    else:
                        self.newfilelist.append('{0}/{1}'.format(url , f_modify(i)))
            return(self.newfilelist)
        elif position == 'st':
            self.newfilelist = []
            #print(self.filelist)
            for i in self.filelist:
                if local:
                    self.newfilelist.append(i)
                else:
                    if self.mode=='pipeline':
                        self.newfilelist.append(  "结题报告/{0}/{1}".format( project,  f_modify(i).replace('./upload/' , '')))
                    else:
                        self.newfilelist.append(  "{0}/{1}".format( url ,  f_modify(i).replace('./upload/' , '')))
            return(self.newfilelist)
        else:    ####for zip file
            if local:
                return(self.zip_path)
            else:
                if self.mode=='pipeline':
                    return('{0}/{1}/{2}'.format(url , project ,  f_modify(self.zip_path)))
                else:
                    return('{0}/{1}'.format(url , f_modify(self.zip_path)))
    def adjust(self):
        '''
        adjust image size and keep w/h raito unchange
        '''
        with Image.open(self.file1) as img:
            width , height  = img.size
            if width/height > 4/3:
                return(600 , height*600/width)
            else :
                return( width*600/height , 600)
    def prepare_directory(self , outdir , bool_upload):
        '''
        copy files into upload file , and modify new file path
        '''
        if bool_upload and self.type:
            new_file_path = '{0}/{1}'.format(outdir ,os.path.basename(self.path))
            self.copy(new_file_path)
            self.path = new_file_path
        else:
            pass
    def zip_files(self , bool_image = False ):
        '''
        zip files and return zip file path
        '''
        output_dir = os.path.dirname(self.path)
        if '*' in output_dir:
            output_dir=glob.glob(output_dir)[0]
        out_zip = '{0}/{1}.zip'.format( output_dir , self.name)
        with zipfile.ZipFile(out_zip,'w',zipfile.ZIP_DEFLATED) as zf:
            for i in self.filelist:
                if bool_image:
                    for j in glob.glob('{0}*'.format(i.rsplit('.',1)[0])):
                        zf.write( j , os.path.basename(j))
                else: 
                    zf.write( i , os.path.basename(i))
        zf.close()
        self.zip_path = out_zip
        return(self.zip_path)
    def copy(self, dest):
        '''
        copy file into upload dirctory
        '''
        dirname = os.path.dirname(os.path.abspath(dest))
        r_list = []
        if not os.path.exists(dirname):
            os.makedirs(dirname)
        for i in self.filelist:   
            #print(i , dest)
            dest = '{0}/{1}'.format(os.path.dirname(dest) , os.path.basename(i))
            copyfile(i , dest)
            r_list.append(dest)
        self.filelist = r_list
        self.file1 = r_list[0]
    def to_json(self, description):
        ''' dumps table into json file with title ,data , label ,descrition
        '''
        tt = {}
        Pathway.group += 1

        for i in self.filelist:
            pp = {"title":[] , "data":[], "label":[] , "description":description}
            header = collections.OrderedDict()
            with open(i) as fin:
                for m,n in enumerate(fin):
                    tmp=n.rstrip().split('\t')
                    if m == 0 :
                        header = {a.replace('.','!') : "int" for a in tmp}
                    else:
                        pp["data"].append(tmp)
                        header = self.modify_type(header , tmp)
            out_json = i.rsplit('.',1)[0] +'.json' 
            self.write_to_json(out_json , pp , header )
            Pathway.sourceKey += 1 
            tt[Pathway.sourceKey] = os.path.basename(out_json)
            Pathway.file_mapping.append({"source": out_json.replace('./upload/','',1) , 
            "sourceKey":"{0}".format(Pathway.sourceKey),
            "group":"g{0}".format(Pathway.group)}) 
        return(tt ,Pathway.group )
    
    def isdecimal(self, value):
        try:
            float(value)
            return(True)
        except ValueError:
            return(False)

    def modify_type(self , header , tmp):
        '''
        Determine the type of title
        '''
        header_list = list(header.keys())
        for i,j in enumerate(tmp):
            a_key = header_list[i]
            if header[a_key] == 'int' :
                if j.isnumeric():
                    pass
                elif self.isdecimal(j):
                    header[a_key] = 'double'
                else:
                    header[a_key] = 'string'
            elif header[a_key] == 'double':
                if not( j.isnumeric() or self.isdecimal(j) ):
                    header[a_key] = 'string'
            else:
                pass
        return(header)
    def write_to_json(self , out_json , pp , header):
        '''
        dumps json
        '''
        for i in header:
            if header[i] =='string':
                pp["title"].append({"ts":"false" , "name":i , "type": header[i]})
            elif header[i] =='double':
                pp["title"].append({"ts":"false" , "name":i , "type": header[i]})
                pp["label"].append(i.replace('!' , '.'))
            else:
                pp["title"].append({"ts":"true" , "name":i , "type": header[i]})
                pp["label"].append(i.replace('!' , '.'))
        with open(out_json , 'w') as f_out :
            f_out.write( json.dumps(pp , indent=4))

def get_md_json(indir , bool_upload , output_dir,url , mode):
    '''
    indir: args.indir 
    bool_upload:
    output_dir  : upload directory
    r_dict->module_name -> json -> [pathway instance]
                        -> md -> md files
    '''
    r_dict = {}
    list_of_files = []
    for root , dirs , files in os.walk(indir):
        list_of_files += [os.path.join(root, file) for file in files]
    for file in list_of_files:
        if file.endswith('input.json'):
            with open(file) as fin:
                name , j_list = json_modify(json.load(fin) , os.path.dirname(file) , output_dir , bool_upload,url ,mode)
            if not name in r_dict : r_dict[name] = {}
            r_dict[name]['json'] = j_list
            md_file = file.replace('input.json' , 'template.md')
            if md_file in list_of_files:
                r_dict[name]['md'] = md_file
            else:
                raise Exception('Error:{0} is not found'.format(md_file))
    #print(r_dict)
    return(r_dict)

def json_modify(json_dict , dirname, outdir, bool_upload,url ,mode):
    '''
    outdir: basename + upload
    dirname:  old file dirname, from work directory to json file
    json_dict : json load dict
    bool_upload:  whether prepare file into upload
    '''
    #print(outdir , bool_upload)
    r_list = []
    name = json_dict['name']   ### module name
    for i in json_dict:
        a_path = Pathway(i , json_dict[i] , name , dirname ,url , mode)   ### dirname is old directory 
        a_path.prepare_directory('{0}/{1}'.format(outdir, name) , bool_upload)
        #print('****',a_path.path)
        r_list.append(a_path)
    return(name , r_list)

def merge_all_md( indir , bool_upload , output_dir , url , mode , function_list=[]):
    '''
    indir:  args.indir 
    bool_upload : whether copy data into a new directory , useful for a pipeline 
    output_dir : output_dir+/upload
    function_list:  order of module list
    '''
    all_dict = get_md_json(indir , bool_upload , output_dir , url, mode)
    if not len(function_list):
        function_list = sorted(all_dict.keys())
    all_md = [all_dict[i]['md'] for i in function_list]
    all_json = { j.name:j for i in function_list for j in all_dict[i]['json'] }
    return(merge_file(all_md) , all_json)


def merge_file(file_list):
    '''
    merge all template file into a list 
    '''
    template_list = []
    for fname in file_list:
        with open(fname) as infile:
            template_list += infile.readlines()
    return( template_list )

def replace_template( template_list , inputs_dict , bool_local , project ,bool_pdf , config):
    '''
    template_list: a list of template file content 
    inputs_dict : a list of pathway object
    bool_local : 
    project : project name 
    '''
    r_list = []
    count = {'table':0 , 'image':0}
    bool_json = False    ### used to store line for json table
    description_list = []
    a_line = ''
    pat3 = re.compile('^\s*$')
    for i in template_list:
        if bool_json:
            if re.search(pat3, i ):continue
            if i.lstrip().startswith('@'):
                a_line.description.append(i.lstrip()[1:])
                continue
            else:
                bool_json = False
                modify_content(a_line, inputs_dict , count , bool_local ,project)
                r_list.append(a_line.out_line)
        a_line = Content(i , config , bool_pdf )
        if a_line.is_contain_variable():
            a_line.type_of_variable()
            if a_line.type == 'json':   
                bool_json = True
                continue
            modify_content(a_line, inputs_dict , count , bool_local ,project)
            r_list.append(a_line.out_line)
        else:
            if a_line.line : 
                if a_line.line[0].isalnum():
                    r_list.append('\n&emsp;&emsp;'+a_line.line)
                else:
                    r_list.append(a_line.line)
            else:
                r_list.append(a_line.line)
    if bool_json:
        modify_content(a_line, inputs_dict , count , bool_local ,project)
        r_list.append(a_line.out_line)
    return r_list 

def modify_content(a_line ,inputs_dict , count ,bool_local ,project ):
    if a_line.variable in inputs_dict:
        a_line.replace_content( inputs_dict , count , bool_local ,project)
    else:
        print('{0} is not defined'.format(a_line.variable))


def find_defined(infile):
    THIS_DIR = os.path.dirname(os.path.abspath(infile))
    env = Environment(loader=FileSystemLoader(THIS_DIR),trim_blocks=True , undefined=StrictUndefined)
    template_source = env.loader.get_source(env , os.path.basename(infile))[0]
    parsed_content = env.parse(template_source)
    a_set = meta.find_undeclared_variables(parsed_content) 
    return(a_set )

def dumps(a_dict):
    '''
    output json from Pathway instance and string 
    '''
    r_dict = {}
    for i in a_dict:
        if isinstance(a_dict[i] , str):
            r_dict[i] = a_dict[i]
        else:
            r_dict[i] = a_dict[i].path
    return(r_dict)

def main():
    parser=argparse.ArgumentParser(description=__doc__,
            formatter_class=argparse.RawDescriptionHelpFormatter,
            epilog='author:\t{0}\nmail:\t{1}'.format(__author__,__mail__))
    parser.add_argument('-d' , '--indir' , help = 'input directory ' , dest='indir' , required=True)
    parser.add_argument('-o','--output',help='output file',dest='output', required=True)
    parser.add_argument('-pdf','--pdf',help='output pdf file',dest='pdf',action='store_true')
    parser.add_argument('-l','--local',help='output local md file , or add url',dest='local',action='store_true')
    parser.add_argument('-u' , '--upload' ,help='whether prepare upload directory' , dest='upload' , action='store_true')
    parser.add_argument('-pipeline' , '--pipeline' ,help='parameters for pipeline , [project_id] ' , dest='pipeline' , nargs=1)
    parser.add_argument('-smalltool' , '--smalltool' ,help='parameters for smalltool , [path , st_id]' , dest='smalltool' , nargs=2)
    args=parser.parse_args()
    

    mode = ''
    parameter = []
    print(args)
    if args.pipeline:
        mode = 'pipeline'
        parameter = ['https://source.solargenomics.com/user/report' ] + args.pipeline  ### url , project 
    elif args.smalltool:
        mode = 'smalltool'
        parameter = ['https://annoroad-cloud-test.oss-cn-beijing.aliyuncs.com'] + args.smalltool  ### url , path , smalltool id 
    else:
        sys.exit()

    if args.output.startswith(r'/'): sys.exit('Error: please -o use relative pathway')
    final_output = args.output
    with open('{0}/config.json'.format(bindir)) as fin:
        config = json.load(fin)

    if not args.output.startswith(r'.'): final_output = './' + args.output
    output_dir = os.path.dirname(final_output)
    if not os.path.exists(output_dir+'/upload'): os.makedirs(output_dir+'/upload')

    template_list , inputs_dict = merge_all_md(args.indir, args.upload , output_dir+'/upload' , parameter , mode ) 

    new_template_list = replace_template( template_list , inputs_dict , args.local , parameter[-1] , args.pdf , config)

    with open('{0}/tmp_template.tmp'.format(output_dir) , 'w') as f_out:
        for i in new_template_list:
            f_out.write(i)
        Content.coder[2] += 1 
        if not args.pdf: 
            f_out.write('### {0}.{1} 结果目录\n'.format(Content.coder[1] , Content.coder[2]))
            f_out.write(config['dir_tree'].format(parameter[-1]))
            f_out.write(config['company'])

    inputs_dict = dumps(inputs_dict)
    pprint(inputs_dict)

    env = Environment(loader=FileSystemLoader(output_dir) , trim_blocks=True , undefined=DebugUndefined)
    template = env.get_template('tmp_template.tmp' )
    with open(final_output,'w') as f_out:
        f_out.write(template.render(**inputs_dict).replace("\n![" , "\n\n!["))
    
    with open('{0}/mapping.json'.format(output_dir) , 'w') as f_out:
        f_out.write( json.dumps( {'file_mapping': Pathway.file_mapping} , indent=4))

    print("\n\nstep2 : check result ")
    a_set = find_defined(final_output)
    if len(a_set):
        print("[Error]: undefined variable is \n{0}\n".format("\n".join(a_set)))


if __name__ == '__main__':
    main()
